package edu.asu.obsolete;


import java.util.ArrayList;
import java.util.Arrays;

import edu.asu.sapa.Planner;
import edu.asu.sapa.ground.MathForm;
import edu.asu.sapa.ground.State;
import edu.asu.sapa.ground.update.Condition;
import edu.asu.sapa.ground.update.Context;
import edu.asu.sapa.ground.update.Update;
import edu.asu.sapa.ground.update.UpdateWrapper;
import edu.asu.sapa.lifted.Action;
import edu.asu.sapa.lifted.Symbol;

public class DelayedInterval {

	public int id;
	public MathForm start;
	public MathForm duration;

	public Update<?>[] startPoint;
	public Update<?>[] allInterval;
	public Update<?>[] endPoint;

	public DelayedInterval() {
		id = 0;
		start = MathForm.NaN;
		duration = MathForm.NaN;
		startPoint = new Update<?>[0];
		endPoint = new Update<?>[0];
		allInterval = new Update<?>[0];
	}
	
	public DelayedInterval(int id) {
		this.id = id;
		start = MathForm.NaN;
		duration = MathForm.NaN;
		startPoint = new Update<?>[0];
		endPoint = new Update<?>[0];
		allInterval = new Update<?>[0];
	}

	public Object clone() {
		DelayedInterval o=null;
		try {
			o = (DelayedInterval)super.clone();
		} catch (CloneNotSupportedException e) {
			// assert false;
		}

		// shallow copies are fine -- if we want to overwrite effects we assign a new reference, not alter the actual effect
		o.startPoint = Arrays.copyOf(startPoint,startPoint.length);
		o.endPoint = Arrays.copyOf(endPoint,endPoint.length);
		o.allInterval = Arrays.copyOf(allInterval,allInterval.length);

		// very shallow copies sufficient
		// this is only used to clone whole groundings, presumably for scratch considerations by Monitor() (i.e., updates)
		// so having top level structures independent is fine; bottom levels can share --
		// we wouldn't be considering altering only part of a duration or cost formula.  Only the whole thing.
		// also, this is really only used for the initOperator anyways.
		o.start = new MathForm(start);
		o.duration = new MathForm(duration);

		return o;
	}

	public void removeDependencies(int id) {
		for (Update<?> u : startPoint) {
			u.removeDependencies(id);
		}
		for (Update<?> u : endPoint) {
			u.removeDependencies(id);
		}
		for (Update<?> u : allInterval) {
			u.removeDependencies(id);
		}

	}

	public float getDuration(State s, Context c) {
		return duration.value(s, c);
	}

	public void setDuration(float f) {
		duration = new MathForm(f);
	}

	public void setDuration(MathForm m) {
		duration = m;
	}

	public String toString() {
		String s = new String();
		s += "(and\n";
		s += "\t(at " + start + " (and\n";
		for (Update u : startPoint)
			s += "\t\t" + u + "\n";
		s += "\t))\n";
		s += "\t(over [" + start + ",^ " + duration + "] (and\n";
		for (Update u : allInterval)
			s += "\t\t" + u + "\n";
		s += "\t))\n";
		s += "\t(at " + start + " + " + duration + " (and\n";
		for (Update u : endPoint)
			s += "\t\t" + u + "\n";
		s += "\t))\n";
		s += ")\n";


		/*
	  		s += ":condition (and";

			for (Condition c : conditionList) {
				s += "\t" + c + "\n";
			}
			for (ProtectCondition c : protectConditionList) {
				s += "\t" + c + "\n";
			}
			for (Test c : testList) {
				s += "\t" + c + "\n";
			}
			for (ProtectTest c : protectTestList) {
				s += "\t" + c + "\n";
			}
			s += "\t)\n";

			s += ":effect (and\n";
			for (Assign c : effectList) {
				s += "\t" + c + "\n";
			}
			for (Set c : setList) {
				s += "\t" + c + "\n";
			}
			s += "\t)\n";

			s += ")\n";
		 */

		return s;
	}

	public boolean analyzeStatic(float dur) {
		boolean isPossible = true;

		if (!start.analyzeStatic(dur)) {
			// only for planning graph
			if(start.value != start.value)
				start.value = 1;
		} else {
			if (start.value != start.value)
				isPossible = false;
		}

		if (!duration.analyzeStatic(dur)) {
			// only for planning graph
			if(duration.value != duration.value)
				duration.value = 1;
		} else {
			dur = duration.value;
			if (dur != dur)
				isPossible = false;
		}

		for (Update<?> u : startPoint) {
			isPossible &= u.analyzeStatic(dur);
		}
		for (Update<?> u : endPoint) {
			isPossible &= u.analyzeStatic(dur);
		}
		for (Update<?> u : allInterval) {
			isPossible &= u.analyzeStatic(dur);
		}

		return isPossible;
	}

	public boolean applicable(State state, Context c) {
		// TODO: Possibly scan ahead to see if there is already a conflict?
		// Difficult to do...
		return true;
	}

	public boolean update(State s) {
		float t = start.value(s,null);
		float d = duration.value(s,null);
		float e = t + d;
		Context cntxt = new Context(id,t,d,e);
		float tEps = t + Planner.EPSILON;
		float eEps = e + Planner.EPSILON;
		for (Update<?> u : startPoint) {
			s.events.add(cntxt,u,UpdateWrapper,t);
			s.events.add(cntxt,u,UpdateWrapper,tEps);
		}
		for (Update<?> u : allInterval) {
			s.events.add(cntxt,u,UpdateWrapper,t);
			s.events.add(cntxt,u,UpdateWrapper,eEps);
		}
		for (Update<?> u : endPoint) {
			s.events.add(cntxt,u,UpdateWrapper,e);
			s.events.add(cntxt,u,UpdateWrapper,eEps);
		}
		return true;
	}

	public int compareTo(DelayedInterval o) {
		if (start.type == MathForm.Constant) {
			if (o.start.type == MathForm.Constant)
				if (start.value <= o.start.value) {
					if (start.value == o.start.value) 
						if (duration.type == MathForm.Constant) {
							if (o.duration.type == MathForm.Constant)
								return (int) (duration.value - o.duration.value);
							else
								return -1;
						} else {
							if (o.duration.type == MathForm.Constant)
								return 1;
							else
								return 0;

						}
					else
						return -1;
				} else {
					return 1;
				}
			else
				return -1;
		} else {
			if (o.start.type == MathForm.Constant)
				return 1;
			else
				if (duration.type == MathForm.Constant) {
					if (o.duration.type == MathForm.Constant)
						return (int) (duration.value - o.duration.value);
					else
						return -1;
				} else {
					if (o.duration.type == MathForm.Constant)
						return 1;
					else
						return 0;
				}

		}
	}

}
